package com.lubase.export.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.fastjson.JSON;
import com.lubase.export.service.ExportsExtendService;
import com.lubase.model.DbCode;
import com.lubase.model.DbEntity;
import com.lubase.model.DbField;
import com.lubase.model.EDBEntityState;
import com.lubase.orm.QueryOption;
import com.lubase.orm.TableFilter;
import com.lubase.orm.exception.WarnCommonException;
import com.lubase.orm.extend.remote.DeptInfoServiceImpl;
import com.lubase.orm.extend.remote.UserInfoByCodeServiceImpl;
import com.lubase.orm.model.DbCollection;
import com.lubase.orm.model.EColumnType;
import com.lubase.orm.service.DataAccess;
import com.lubase.orm.util.TableFilterWrapper;
import com.lubase.orm.util.TypeConverterUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class ExportsExtendServiceImpl implements ExportsExtendService {
    @Autowired
    DataAccess dataAccess;
    @Autowired
    UserInfoByCodeServiceImpl userInfoByCodeService;
    @Autowired
    DeptInfoServiceImpl deptInfoService;
    @Override
    public void ExportByIds(String TableId, String Ids, HttpServletResponse response) throws IOException {
        String TableName = dataAccess.getEmptyDataByTableId(Long.parseLong(TableId)).getTableName();
        QueryOption queryOption = new QueryOption(TableName, 0, 0);
        TableFilterWrapper wrapper = new TableFilterWrapper(true);
        wrapper.in("ID", Ids);
        queryOption.setTableFilter(wrapper.build());
        queryOption.setFixField("*");
        DbCollection collection = dataAccess.query(queryOption);
        ExportByQuery(collection, response, TableName+"导出",".xlsx");
    }

    @Override
    public void ExportByQuery(DbCollection collection, HttpServletResponse response, String name, String suffixes) throws IOException {
        //表头
        List<List<String>> headList = new ArrayList<List<String>>();
        List<String> codes = new ArrayList<>();
        HashMap<String, String> codeType = new HashMap<String, String>();
        HashMap<String, DbCollection> codeList = new HashMap<String, DbCollection>();
        if(!suffixes.matches(".xlsx") || !suffixes.matches(".xls")|| !suffixes.matches(".csv"))
        {
            suffixes = ".xlsx";
        }
        for (DbField filed : collection.tableInfo.getFieldList()) {
            //跳过主键
            if (filed.getName().equals("主键")) {
                continue;
            } else if (filed.getCodeTypeId() != null && !StringUtils.isEmpty(filed.getCodeTypeId())) {
                //获取码表信息
                DbCollection t = getCodeType(filed.getCodeTypeId());
                codeList.put(filed.getCode(), t);
            }
            List<String> tmp = new ArrayList(1);
            tmp.add(filed.getName());
            codes.add(filed.getCode());
            headList.add(tmp);
        }
        List<List<String>> contentList = new ArrayList<List<String>>();

        List<DbEntity> dataList = collection.getData();
        for (DbEntity DbEntity : dataList) {
            List<String> tmp = new ArrayList();
            for (String code : codes) {
                if (DbEntity.get(code) != null && !(DbEntity.get(code).equals(""))) {
                    //获取码表信息
                    DbCollection t = codeList.get(code);
                    int a = 0;
                    if (t != null) {
                        for (DbEntity dmCode : t.getData()) {
                            if (dmCode.get("code_value").toString().equals(DbEntity.get(code))) {
                                tmp.add(dmCode.get("code_name").toString());
                                a++;
                            }
                        }
                    }
                    //如果码值没有
                    if (0 == a) {
                        String rowValue = TypeConverterUtils.object2String(DbEntity.getRefData().get(code + "NAME"));
                        if (rowValue == null) {
                            tmp.add(DbEntity.get(code).toString());
                        } else {
                            tmp.add(rowValue);
                        }
                    }
                } else {
                    tmp.add("");
                }
            }
            contentList.add(tmp);
        }
        //excel文件名
        final String FILENAME = name + "-" + LocalDateTime.now().toString().substring(0, 10);
        //sheetName
        final String SHEETNAME = name + "-" + LocalDateTime.now().toString().substring(0, 10);
        try {
            //表头样式策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            WriteFont writeFont = new WriteFont();
           // writeFont.setColor((short)50);
            headWriteCellStyle.setWriteFont(writeFont);
            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
            WriteFont contentWriteFont = new WriteFont();
            //contentWriteFont.setColor((short)12);
            contentWriteCellStyle.setWriteFont(contentWriteFont);
            //初始化表格样式
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            String fileName = URLEncoder.encode(FILENAME, "UTF-8").replaceAll("\\+", "%20");
            //响应首部 Access-Control-Expose-Headers 就是控制“暴露”的开关，它列出了哪些首部可以作为响应的一部分暴露给外部。
            //此处设置了开放Content-Disposition，前端可获取该响应参数获取文件名称
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + suffixes);
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream()).autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(horizontalCellStyleStrategy).sheet(SHEETNAME).head(headList).doWrite(contentList);
        } catch (IOException e) { //下载失败情况的处理
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }
    @Override
    public void ExportModel(String tableName,String tableId, HttpServletResponse response) throws IOException {
        if(StringUtils.isEmpty(tableName))
        {
             tableName = dataAccess.getEmptyDataByTableId(Long.parseLong(tableId)).getTableName();
        }
        //表头
        List<List<String>> headList = new ArrayList<List<String>>();
        DbCollection importCollect = dataAccess.getEmptyData(tableName);
        List<List<String>> contentList = new ArrayList<List<String>>();
        for (DbField filed : importCollect.tableInfo.getFieldList()) {
            //跳过主键
            if (filed.getName().equals("主键")||filed.getCode().equals("create_by")||filed.getCode().equals("create_time")||filed.getCode().equals("update_time")||filed.getCode().equals("update_by")||filed.getEleType().equals(EColumnType.Document.getIndex().toString())||filed.getEleType().equals(EColumnType.Image.getIndex().toString())) {
                continue;
            }
            List<String> tmpName = new ArrayList();
            tmpName.add("导入模板提示");
            tmpName.add(GetTip(filed));
            tmpName.add(filed.getName());
            headList.add(tmpName);
        }


        //excel文件名
        final String FILENAME = String.format("%s-%s", importCollect.tableInfo.getName(),"模板");
        //sheetName
        final String SHEETNAME = importCollect.tableInfo.getName() + "-" + LocalDateTime.now().toString().substring(0, 10);
        try {
            //表头样式策略
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
            //初始化表格样式
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            String fileName = URLEncoder.encode(FILENAME, "UTF-8").replaceAll("\\+", "%20");
            //响应首部 Access-Control-Expose-Headers 就是控制“暴露”的开关，它列出了哪些首部可以作为响应的一部分暴露给外部。
            //此处设置了开放Content-Disposition，前端可获取该响应参数获取文件名称
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream()).autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(horizontalCellStyleStrategy).sheet(SHEETNAME).head(headList).doWrite(contentList);
        } catch (IOException e) { //下载失败情况的处理
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }
    }
    @SneakyThrows
    @Override
    public boolean Import(String tableName,String tableId, MultipartFile file) throws IOException {
        if(StringUtils.isEmpty(tableName))
        {
            tableName = dataAccess.getEmptyDataByTableId(Long.parseLong(tableId)).getTableName();
        }
        InputStream inputStream=null;
        inputStream= file.getInputStream();
        DbCollection importCollect = dataAccess.getEmptyData(tableName);
        //码表
        List<String> codes = new ArrayList<>();
        //类型
        List<String> eleTypes = new ArrayList<>();
        //表头
        List<List<String>> headList = new ArrayList<List<String>>();
        //关联码表
        Map<String, String> codeTypeMap = MapUtils.newHashMap();
        //系统服务表
        Map<String, String> sysTemMap = MapUtils.newHashMap();
        for (DbField filed : importCollect.tableInfo.getFieldList()) {
            //跳过主键
            if (filed.getName().equals("主键")||filed.getCode().equals("create_by")||filed.getCode().equals("create_time")||filed.getCode().equals("update_time")||filed.getCode().equals("update_by")||filed.getEleType().equals("8")||filed.getEleType().equals("9")) {
                continue;
            }
            List<String> tmp = new ArrayList<>(1);
            tmp.add("导入模板提示");
            tmp.add(GetTip(filed));
            tmp.add(filed.getName());
            codes.add(filed.getCode());
            eleTypes.add(filed.getEleType());
            if(filed.getEleType().equals(EColumnType.CodeData.getIndex().toString()))
            {
                codeTypeMap.put(filed.getCode(),filed.getCodeTypeId());
            } else if(filed.getEleType().equals("10"))
            {
                sysTemMap.put(filed.getCode(),filed.getServiceName());
            }
            headList.add(tmp);
        }
        try {
            List<LinkedHashMap<String,String>> objectList=EasyExcel.read(inputStream).head(headList).doReadAllSync();
            List<DbEntity> entityList = new ArrayList<>();
            for (LinkedHashMap<String, String> stringStringLinkedHashMap : objectList) {
                DbEntity en = new DbEntity();
                for (int line = 0; line < stringStringLinkedHashMap.size(); line++) {
                    String cell= TypeConverterUtils.object2String(stringStringLinkedHashMap.get(line));
                    if(cell!=null)
                    {
                        if(eleTypes.get(line).equals(EColumnType.CodeData.getIndex().toString()))
                        {
                            List<DbCode> list = dataAccess.getCodeListByTypeId(codeTypeMap.get(codes.get(line)));
                            for (var dbcode:list) {
                                if(cell.equals(dbcode.getName()))
                                {
                                    cell=dbcode.getCode();
                                }
                            }
                        }else if(eleTypes.get(line).equals("10"))
                        {
                            //用户扩展
                            if("userColumnServiceImpl".equals(sysTemMap.get(codes.get(line))))
                            {
                             DbEntity userInfo =  userInfoByCodeService.getCacheDataByKey(cell);
                                log.info("进入userColumnServiceImpl");

                                if(userInfo.get("id")!=null)
                                {
                                    cell=userInfo.get("id").toString();
                                }
                            }
                            //组织扩展
                            else if ("userOrgIdColumnServiceImpl".equals(sysTemMap.get(codes.get(line))))
                            {
                                QueryOption queryOption = new QueryOption("sa_organization");
                                queryOption.setTableFilter(new TableFilter("org_name", cell));
                                DbCollection db=  deptInfoService.getDataByFilter(queryOption,"");
                                if(db.getData().size()>0)
                                {
                                    cell=db.getData().get(0).get("id").toString();
                                }
                            }
                        }
                    }
                    en.put(codes.get(line), cell);
                }

                en.setState(EDBEntityState.Added);
                entityList.add(en);
            }
            importCollect.setData(entityList);
            importCollect.setEnableTableTrigger(false);
            int i= dataAccess.update(importCollect);
            log.info("导入成功{}行",i);
        } catch (Exception e) {
            //导入失败情况的处理
            log.error("导入失败:",e);
            throw new WarnCommonException("导入失败"+e.getMessage());
        }
        return  true;
    }

    private DbCollection getCodeType(String code_type_id) {
        QueryOption queryOption = new QueryOption("dm_code", 0, 0);
        TableFilterWrapper wrapper = new TableFilterWrapper(true);
        wrapper.eq("code_type_id", code_type_id);
        queryOption.setTableFilter(wrapper.build());
        queryOption.setFixField("*");
        DbCollection codeCollection = dataAccess.query(queryOption);
        return codeCollection;
    }

    @Override
    public void ExportByQueryAll(QueryOption serverQuery, HttpServletResponse response, String name, String suffixes) throws IOException {
        DbCollection collection = dataAccess.queryAllData(serverQuery);
        ExportByQuery(collection, response, name,suffixes);
    }
    private String GetTip(DbField filed )
    {
        String tip="";
        if (filed.getEleType().equals(EColumnType.Numeric.getIndex().toString()) || filed.getEleType().equals(EColumnType.Int.getIndex().toString())) {
            tip="请填写数字,例：12";
        } else if (filed.getEleType().equals(EColumnType.Date.getIndex().toString())) {
            String Format = "yyyy-MM-dd HH:mm:ss";
            if (filed.getDataFormat() != null) {
                Format = filed.getDataFormat();
            }
            tip="请填日期,格式："+Format;
        } else if (filed.getEleType().equals(EColumnType.Boolean.getIndex().toString())) {
            tip="请填写true或者false";
        }else if(filed.getEleType().equals(EColumnType.Lookup.getIndex().toString()))
        {
            tip="关联字段,如需导入请属入关联表相应主键";

        }else if(filed.getEleType().equals("10"))
        {
            String componentPath = filed.getServiceName();
            if(componentPath.equals("userColumnServiceImpl")){
                tip="请输入用户,例：张三(工号)或者工号";
            }
            else if (componentPath.equals("deptInfoServiceImpl")){
                tip="请输入部门名称";
            }else {
                tip="参考服务列："+componentPath+"配置";
            }
        }else if(filed.getEleType().equals(EColumnType.CodeData.getIndex().toString()))
        {
            if(null!=filed.getCodeTypeId()) {
                List<DbCode> list = dataAccess.getCodeListByTypeId(filed.getCodeTypeId());
                List<String> TmpCodeList =new ArrayList<>();
                for (var dbcode:list) {
                    TmpCodeList.add(dbcode.getName());
                }
                tip="关联码表："+StringUtils.join(TmpCodeList,';');
            }
        }
        else
        {
            tip="请输入字符串，例：张三";
        }
        return  tip;
    }
}
